<?php
namespace app\controller\api;

use app\exception\ErrnoPlus;
use app\service\AccountService;
use app\service\AliyunProxyService;
use app\service\ProjectInfoService;
use app\service\UserDeviceBindingService;
use app\service\UserDeviceShareRuleService;
use app\service\UserDeviceShareService;
use app\service\UserLogService;
use app\validate\DeviceValidate;
use share\controller\ApiBaseController;
use share\service\cache\CommonCacheKeyService;
use share\service\ContextService;
use share\service\RedisService;
use share\service\SendCodeService;
use share\service\UserBaseService;
use share\service\UserDetailService;
use share\utils\Helper;
use think\Log;

class DeviceController extends ApiBaseController{

    protected $beforeActionList = [
        "checkSign",
        "checkUser", 
    ];

    /**
     * @description: 
     * @return {*}
     * @use: 
     */
    public function initValidate(){
        $this->validate = new DeviceValidate();
    }

    /**
     * 获取用户所有设备信息
     */
    public function all_action(){
        $userInfo = ContextService::getUserInfo();

        $res = [];

        // 获取用户分享的设备
        $shareUserData = UserDeviceShareService::getAllByShareUser($userInfo['id']);

        // 获取用户绑定的设备
        $bindingData = UserDeviceBindingService::getAllByUser($userInfo['id']);


        // 用户绑定设备分享出去的信息
        $shareDeviceData = [];

        
        if($bindingData){
            $iotIds = array_column($bindingData,'iot_id');
            $shareDeviceData = UserDeviceShareService::getAllByMainId($iotIds);
        }

        $shareUids = Helper::arraySmartUnique(array_column($shareDeviceData,'share_uid'));
        $shareMainUids = Helper::arraySmartUnique(array_column($shareUserData,'admin_uid'));
        $allUserId = Helper::arraySmartUnique(array_merge($shareUids,$shareMainUids));
        
        $shareUserInfo = UserBaseService::getAll($allUserId);        
        if($shareDeviceData){
            $shareUserDetail = UserDetailService::getAll($allUserId);
        }

        $shareIds = array_column($shareUserData,'id');
        $shareIds = Helper::arraySmartUnique(array_merge(array_column($shareDeviceData,'id'),$shareIds));

        $shareRules = UserDeviceShareRuleService::getAllByIds($shareIds);

        foreach($shareUserData as $shareData){
            $mainUser = Helper::filterOne($shareUserInfo,['id'=>  $shareData['admin_uid']]);
            $rule = Helper::filterOne($shareRules,['id'=>  $shareData['id']]);
            $res[] = [
                "iotId" => $shareData["iot_id"],
                "owned" => 0,
                "userId" => $mainUser ? $mainUser['user_id'] : '',
                "userIdentity" => $mainUser ? $mainUser['identity_id'] : '',
                "rule" => $rule['rule'],
            ];
        }

        foreach($bindingData as $bind){
            $tmp = [
                "iotId" => $bind['iot_id'],
                "owned" => 1,
                "userId" => $userInfo["user_id"],
                "userIdentity" => $userInfo["identity_id"],
                "shareInfo" => []
            ];
            if($shareDeviceData){
                $shareDevices =  Helper::filter($shareDeviceData,['main_id'=>$bind['iot_id']]);
                if($shareDevices){
                    foreach($shareDevices as $shareDevice){
                        $currentShareUser = Helper::filterOne($shareUserInfo,['id' => $shareDevice['share_uid']]);
                        $currentUserDetail = Helper::filterOne($shareUserDetail,['id' => $shareDevice['share_uid']]);
                        $rule  = Helper::filterOne($shareRules,['id'=>  $shareDevice['id']]);
                        $tmp['shareInfo'][] = [
                            "shareId" => $currentShareUser ? $currentShareUser['user_id'] :'',
                            "nickName" => $currentUserDetail ? $currentUserDetail['nick_name']:'',
                            "picture" => $currentUserDetail ? $currentUserDetail['picture']:'',
                            "rule" => $rule['rule'],
                            "shareIdentity" => $currentShareUser ? $currentShareUser['identity_id']:'',
                        ];
                    }
                }
            }
            $res[] = $tmp;
        }
  
        return self::ok($res);
    }

    /**
     * 发送设备迁移验证码
     */
    public function send_transfer_code_action(){
        $input = $this->check();
        $userInfo = ContextService::getUserInfo();
        $uid = $userInfo['id'];
        $vendor = $userInfo['vendor'];
        $package = ContextService::getPackageName();
        $ip = ContextService::getIP();
        $receiverUser = self::getReceiverUser($input['account'],$vendor);
        if(empty($receiverUser)){
            return self::fail("receiver account not exists!",ErrnoPlus::USER_NOT_EXISTS);
        }
        else{
            if(empty($receiverUser['identity_id'])){
                return self::fail("receiver account state error (identity_id empty)!",ErrnoPlus::USER_NOT_EXISTS);
            }
        }
        $userDetail = UserDetailService::getBase($uid);
        $receiverUserDetail = UserDetailService::getBase($receiverUser['id']);
        if(empty($receiverUserDetail)){
            return self::fail("receiver user detail not exists!",ErrnoPlus::USER_NOT_EXISTS);
        }
        if($userDetail['server_site'] != $receiverUserDetail['server_site']){
            return self::fail("user server_site is diff!",ErrnoPlus::PARAM_ERROR);
        }
        
        $param = [
            'phoneCode' => $userDetail['phone_code'],
            'isoCode' => $userDetail['location'],
            'language' => $userDetail['server_site'],
        ];
        if(isset($input['accessToken']) && !empty($input['accessToken'])){
            $param['accessToken'] = $input['accessToken'];
        }

        if(!empty($userInfo['email'])){
            AccountService::sendTransferCodeByEmail($userInfo['email'],$param,$vendor,$package);
        }
        else{
            AccountService::sendTransferCodeByPhone($userInfo['phone'],$param,$ip,$vendor,$package);
        }
        return self::ok();
    }

    /**
     * 检验设备迁移验证码
     */
    public function verify_transfer_code_action(){
        $input = $this->check();
        $userInfo = ContextService::getUserInfo();
        $uid = $userInfo['id'];
        $vendor = $userInfo['vendor'];
        $receiverUser = self::getReceiverUser($input['account'],$vendor);
        if(empty($receiverUser)){
            return self::fail("receiver account not exists!",ErrnoPlus::USER_NOT_EXISTS);
        }
        else{
            if(empty($receiverUser['identity_id'])){
                return self::fail("receiver account state error (identity_id empty)!",ErrnoPlus::USER_NOT_EXISTS);
            }
        }
        $userDetail = UserDetailService::getBase($uid);
        $receiverUserDetail = UserDetailService::getBase($receiverUser['id']);
        if(empty($receiverUserDetail)){
            return self::fail("receiver user detail not exists!",ErrnoPlus::USER_NOT_EXISTS);
        }
        if($userDetail['server_site'] != $receiverUserDetail['server_site']){
            return self::fail("user server_site is diff!",ErrnoPlus::PARAM_ERROR);
        }
        
        $sendCodeService = SendCodeService::instance(
            SendCodeService::SEND_CODE_SCENE_TRANSFER_DEVICE,
            !empty($userInfo['email']) ?  SendCodeService::SEND_CODE_SEND_TYPE_OF_EMAIL :SendCodeService::SEND_CODE_SEND_TYPE_OF_PHONE ,
            !empty($userInfo['email']) ?  $userInfo['email'] : $userInfo['phone']
        );
        $code = $sendCodeService->getCode();
        if (empty($code)) { // code 已过期
            return self::fail("this verification code is out time!",ErrnoPlus::VERIFICATION_CODE_OUTTIME);
        }
        if ($code !== $input["code"]) {
            return self::fail("verification code error!",ErrnoPlus::VERIFICATION_CODE_ERROR);
        }
        $sendCodeService->clear();
        
        $token = md5(date("HisYmd").mt_rand(1000,9999)."transfer");
        $devices = AliyunProxyService::getUserAllDeviceInfo($uid);
        if(empty($devices)){
            return self::fail("can not get any devices by current user!",ErrnoPlus::PARAM_ERROR);
        }
        $usefulDevices = Helper::filter($devices,['owned' => 1]);
        if(empty($usefulDevices)){ 
            return self::fail("can not get any device as admin by current user!",ErrnoPlus::PARAM_ERROR);
        }
        $data = [
            'uid' => $uid,
            'devices' => $usefulDevices,
        ];
        RedisService::instance(RedisService::CACHE_DB_BASE)->setJson(CommonCacheKeyService::getCacheKey(CommonCacheKeyService::CACHE_KEY_OF_USER_TRANSFER_DEVICE_TOKEN,[
            'token' => $token
        ]),$data,3600);
        return self::ok([
            'transferToken' => $token,
        ]);
    }

    /**
     * 设备迁移
     */
    public function transfer_action(){
        $input = $this->check();
        $userInfo = ContextService::getUserInfo();
        $uid = $userInfo['id'];
        $vendor = $userInfo['vendor'];
        $receiverUser = self::getReceiverUser($input['account'],$vendor);
        if(empty($receiverUser)){
            return self::fail("receiver account not exists!",ErrnoPlus::USER_NOT_EXISTS);
        }
        else{
            if(empty($receiverUser['identity_id'])){
                return self::fail("receiver account state error (identity_id empty)!",ErrnoPlus::USER_NOT_EXISTS);
            }
        }
        $userDetail = UserDetailService::getBase($uid);
        $receiverUserDetail = UserDetailService::getBase($receiverUser['id']);
        if(empty($receiverUserDetail)){
            return self::fail("receiver user detail not exists!",ErrnoPlus::USER_NOT_EXISTS);
        }
        if($userDetail['server_site'] != $receiverUserDetail['server_site']){
            return self::fail("user server_site is diff!",ErrnoPlus::PARAM_ERROR);
        }
        $tokenKey = CommonCacheKeyService::getCacheKey(CommonCacheKeyService::CACHE_KEY_OF_USER_TRANSFER_DEVICE_TOKEN,[
            'token' => $input['transferToken']
        ]);
        $data = RedisService::instance(RedisService::CACHE_DB_BASE)->getJson($tokenKey);
        if(empty($data)){
            return self::fail("transferToken is expired !",ErrnoPlus::PARAM_ERROR);
        }
        if($data['uid'] !== $uid){
            return self::fail("can not access with current token !",ErrnoPlus::INVALID_PARAM);
        }
        $allowDevices = $data['devices'];
        $devices = $input['devices'];
        $count = count($devices);
        if($count > 20){
            return self::fail("too many devices to transfer !",ErrnoPlus::INVALID_PARAM);
        }
        if($count < 1){
            return self::fail("transfer devices is empty",ErrnoPlus::INVALID_PARAM);
        }
        $changeDevices = [];
        $allowIotIds = array_column($allowDevices,'iotId');
        foreach($devices as $device){
            $tmp = $this->check('deviceList',$device);
            // checkAccess
            if(!in_array($tmp['iotId'],$allowIotIds)){
                return self::fail("no access to transfer device:".$tmp['iotId'],ErrnoPlus::INVALID_PARAM);
            }
            //self::checkAccess($tmp,$allowDevices);
            $changeDevices[] = $tmp;
        }
        
        $projectId = ProjectInfoService::getProjectIdByVendor($vendor);
        if(empty($projectId)){            
            trace("unknown projectId for vendor ".$vendor,Log::ERROR);
            return;
        }
        $aliyunParam = [
            'projectId' =>  $projectId,
            'region' => $receiverUserDetail['server_site'],
        ];
        UserLogService::addLogAsync($userInfo['phone'].$userInfo['email'],$input,UserLogService::ACTION_OF_DEVICE_TRANSFER);
        $aliyunService = AliyunProxyService::getAliyunService($aliyunParam);
        try{
            $res = $aliyunService->userBatchBind($receiverUser['identity_id'],array_column($changeDevices,'iotId'));
            return self::ok([
                'count' => $count,
                'resp' => $res,
            ]);
        }catch(\Exception $e){
            return self::fail("bindError msg:".$e->getMessage(),ErrnoPlus::COMMON_ERROR);
        }        
    }

    public static function getReceiverUser($account,$vendor){
        $receiverUser = AccountService::getByAccount($account,[
            'vendor' => $vendor
        ]);
        return $receiverUser;
    }

    // public static function checkAccess($device,$allowDevices){
    //     $iotId = 
    // }
}